#!/bin/bash

# This script starts two MySQL docker containers in a primary-replica setup
# which can be used for running the replica tests in localtests/ .
# Set the environment var TEST_MYSQL_IMAGE to change the docker image.
#
# Usage:
#   docker-gh-ost-replica-tests up [-t]     start the containers
#   docker-gh-ost-replica-tests down        remove the containers
#   docker-gh-ost-replica-tests run [-t]    run replica tests on the containers
#
# Flags:
#   -t      use a toxiproxy for replica connection to simulate dropped connections

set -e
toxiproxy=false

GH_OST_ROOT=$(git rev-parse --show-toplevel)
if [[ ":$PATH:" != *":$GH_OST_ROOT:"* ]]; then
    export PATH="${PATH}:${GH_OST_ROOT}/script"
fi

poll_mysql() {
    CTR=0
    cmd="gh-ost-test-mysql-$1"
    while ! $cmd -e "select 1;" >/dev/null 2>&1; do
        sleep 1
        CTR=$((CTR + 1))
        if [ $CTR -gt 30 ]; then
            echo " ❌ MySQL $1 failed to start"
            return 1
        fi
    done
    echo " ✔ MySQL $1 OK"
    return 0
}

mysql-source() {
    if [[ $TEST_MYSQL_IMAGE =~ "mysql:8.4" ]]; then
        gh-ost-test-mysql-master --ssl-mode=required "$@"
    else
        gh-ost-test-mysql-master "$@"
    fi
}

mysql-replica() {
    if [[ $TEST_MYSQL_IMAGE =~ "mysql:8.4" ]]; then
        gh-ost-test-mysql-replica --ssl-mode=required "$@"
    else
        gh-ost-test-mysql-replica "$@"
    fi
}

create_toxiproxy() {
    curl --fail -X POST http://localhost:8474/proxies \
        -H "Content-Type: application/json" \
        -d '{"name": "mysql_proxy",
            "listen": "0.0.0.0:23308",
            "upstream": "host.docker.internal:3308"}'
    echo

    curl --fail -X POST http://localhost:8474/proxies/mysql_proxy/toxics \
        -H "Content-Type: application/json" \
        -d '{"name": "limit_data_downstream",
            "type": "limit_data",
            "attributes": {"bytes": 1000000}}'
    echo
}

setup() {
    [ -z "$TEST_MYSQL_IMAGE" ] && TEST_MYSQL_IMAGE="mysql:8.0.41"

    echo "Starting MySQL $TEST_MYSQL_IMAGE containers..."
    compose_file="$GH_OST_ROOT/localtests/docker-compose.yml"
    MYSQL_SHA2_RSA_KEYS_FLAG=""
    MYSQL_PASSWORD_HASHING_ALGORITHM="mysql_native_password"
    if [[ $TEST_MYSQL_IMAGE =~ "mysql:8.4" ]]; then
        MYSQL_PASSWORD_HASHING_ALGORITHM="caching_sha2_password"
        MYSQL_SHA2_RSA_KEYS_FLAG="--caching-sha2-password-auto-generate-rsa-keys=ON"
    fi
    (TEST_MYSQL_IMAGE="$TEST_MYSQL_IMAGE" MYSQL_SHA2_RSA_KEYS_FLAG="$MYSQL_SHA2_RSA_KEYS_FLAG" envsubst <"$compose_file") >"$compose_file.tmp"

    if [ "$toxiproxy" = true ]; then
        echo "Starting toxiproxy container..."
        cat <<EOF >>"$compose_file.tmp"
  mysql-toxiproxy:
    image: "ghcr.io/shopify/toxiproxy:latest"
    container_name: mysql-toxiproxy
    ports:
      - '8474:8474'
      - '23308:23308'
    expose:
      - '23308'
      - '8474'
EOF
    fi

    docker compose -f "$compose_file.tmp" up -d --wait

    echo "Waiting for MySQL..."
    poll_mysql "master" || exit 1
    poll_mysql "replica" || exit 1

    echo -n "Setting up replication..."
    mysql-source -e "create user if not exists 'repl'@'%' identified with $MYSQL_PASSWORD_HASHING_ALGORITHM by 'repl';"
    mysql-source -e "grant replication slave on *.* to 'repl'@'%'; flush privileges;"
    mysql-source -e "create user if not exists 'gh-ost'@'%' identified with $MYSQL_PASSWORD_HASHING_ALGORITHM by 'gh-ost';"
    mysql-source -e "grant all on *.* to 'gh-ost'@'%';"

    sleep 1
    if [[ $TEST_MYSQL_IMAGE =~ "mysql:8.4" ]]; then
        mysql-replica -e "change replication source to source_host='mysql-primary', source_port=3307, source_user='repl', source_password='repl', source_auto_position=1, source_ssl=1;"
        mysql-replica -e "start replica;"
    else
        mysql-replica -e "change master to master_host='mysql-primary', master_port=3307, master_user='repl', master_password='repl', master_auto_position=1;"
        mysql-replica -e "start slave;"
    fi
    echo "OK"

    if [ "$toxiproxy" = true ]; then
        echo "Creating toxiproxy..."
        create_toxiproxy
        echo "OK"
    fi
}

teardown() {
    echo "Stopping containers..."
    docker stop mysql-replica
    docker stop mysql-primary
    docker stop mysql-toxiproxy 2>/dev/null || true
    echo "Removing containers..."
    docker rm mysql-replica
    docker rm mysql-primary
    docker rm mysql-toxiproxy 2>/dev/null || true
}

main() {
    local cmd="$1"
    local tflag=
    if [[ "$2" == "-t" ]]; then
        toxiproxy=true
    fi
    if [[ "$cmd" == "up" ]]; then
        setup
    elif [[ "$cmd" == "down" ]]; then
        teardown
    elif [[ "$cmd" == "run" ]]; then
        shift 1
        "$GH_OST_ROOT/localtests/test.sh" -d "$@"
    fi
}

main "$@"
